<?php
declare(strict_types=1);

namespace Lshorz\LaravelConfig;

use Illuminate\Filesystem\Filesystem;
use Illuminate\Config\Repository;
use Lshorz\LaravelConfig\Events\Updated;
use Lshorz\LaravelConfig\Events\Destroy;

class FileCfgHandler extends CfgHandlerAbstract implements CfgHandlerInterface
{
    /**
     * @var \Illuminate\Config\Repository;
     */
    protected Repository $config;

    /**
     * @var \Illuminate\Filesystem\Filesystem;
     */
    protected Filesystem $files;

    /**
     * 配置文件保存路径
     * @var string
     */
    protected string $path;

    public function __construct(Repository $config, Filesystem $files)
    {
        $this->config = $config;
        $this->files = $files;
    }

    /**
     * 选择配置标识
     *
     * @param string|null $identifier 文件名|配置名|keys
     * @return $this
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
     */
    public function init(?string $identifier = null): self
    {
        if ($identifier) {
            $this->setIdentifier($identifier, 'file');
            $this->path = $this->config->get('cfg.file.path') . "/" . $identifier;
        } else {
            $this->setIdentifier($this->config->get('cfg.default_identifier'), 'file');
            $this->path = $this->config->get('cfg.file.path') . "/" . $this->config->get('cfg.default_identifier');
        }

        $this->items = $this->getCfgItems();

        return $this;
    }

    /**
     * 验证配置
     *
     * @return bool
     */
    public function valid(): bool
    {
        return !empty($this->items);
    }

    /**
     * 获取配置列表
     *
     * @return array
     */
    public function index(): array
    {
        $result = [];
        $cfgFiles = $this->files->files($this->config->get('cfg.file.path'));
        if (!empty($cfgFiles)) {
            foreach ($cfgFiles as $key => $cfgFile) {
                $result[$key]['identifier'] = $cfgFile->getFilename();
                $result[$key]['path'] = $cfgFile->getPath();
                $result[$key]['created_at'] = date('Y-m-d H:i:s', $cfgFile->getCTime());
                $result[$key]['updated_at'] = date('Y-m-d H:i:s', $cfgFile->getMTime());
            }
        }
        return $result;
    }

    /**
     * 创建配置
     *
     * @param array $items ;
     * @return bool
     */
    public function create(array $items): bool
    {
        //检查是否存在同名的配置
        if ($this->files->exists($this->path)) {
            return false;
        } else {
            $this->set($items);
            return $this->store();
        }
    }

    /**
     * 更新配置
     *
     * @param string|null $key
     * @param mixed $value
     * @return bool
     */
    public function update(?string $key, $value): bool
    {
        if (is_null($key)) {
            $this->items = $value;
        } else {
            $this->set($key, $value);
        }

        return $this->store();
    }

    /**
     * 销毁配置
     *
     * @return bool
     */
    public function destroy(): bool
    {
        if ($this->files->delete($this->path)) {
            $this->cacheDestroy();
            event(new Destroy($this->getIdentifier()));
            return true;
        } else {
            return false;
        }
    }

    /**
     * 保存配置
     *
     * @return bool
     */
    public function store(): bool
    {
        if ($this->files->put($this->path, serialize($this->items))) {
            event(new Updated($this->getIdentifier(), $this->items));
            $this->cacheDestroy();
            return true;
        } else {
            return false;
        }
    }

    /**
     * 设置配置值
     *
     * @param array|string $key
     * @param mixed $value
     * @return self
     */
    public function set($key, $value = null): self
    {
        return parent::set($key, $value);
    }

    /**
     * 将值插入到数组配置值前面
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return self
     */
    public function prepend(string $key, $value): self
    {
        return parent::prepend($key, $value);
    }

    /**
     * 值插入到数组配置值后面
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return self
     */
    public function push(string $key, $value): self
    {
        return parent::push($key, $value);
    }

    /**
     * 获取并初始化配置
     *
     * @return mixed
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
     */
    private function getCfgItems()
    {
        $result = $this->cacheGet() ?? [];

        if (empty($result)) {
            if ($this->files->exists($this->path)) {
                $result = unserialize($this->files->get($this->path));
                if (is_array($result) && !empty($result)) {
                    $this->cacheCreate($result);
                }
            }
        }

        return $result;
    }
}
